﻿#region license
// Copyright (c) 2008 - 2008 Ritesh Rao
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
// 
//     * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//     * Neither the name of Ayende Rahien nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion

using System;
using System.Collections.Generic;
using NCommon;

namespace Rhinestone.Domain
{
    /// <summary>
    /// A work item that users can submit, comment on and track.
    /// </summary>
    public class WorkItem
    {
        #region fields
        private int _workItemID;
        private Project _project;
        private readonly DateTime _created;
        private readonly DateTime _modified;
        private readonly IUser _createdBy;
        private readonly ICollection<WorkItem> _relatedItems = new HashSet<WorkItem>();
        private readonly ICollection<Comment> _comments = new HashSet<Comment>();
        private readonly ICollection<Attachment> _attachments = new HashSet<Attachment>();
        #endregion

        #region .ctor
        /// <summary>
        /// Inherited constructor.
        /// </summary>
        protected WorkItem() {}

        /// <summary>
        /// Default Constructor.
        /// Creates a new instance of the <see cref="WorkItem"/> class.
        /// </summary>
        /// <param name="createdBy">A <see cref="IUser"/> instance representing the user
        /// who has created this WorkItem instance.</param>
        public WorkItem(IUser createdBy)
        {
            Guard.Against<ArgumentNullException>(createdBy == null, "Cannot create a WorkItem instance from a null reference in createdBy");
            DateTime now = DateTime.Now;
            _createdBy = createdBy;
            _created = now;
            _modified = now;
        }
        #endregion

        #region properties
        /// <summary>
        /// Gets the unique ID assigned to the work item instance.
        /// </summary>
        /// <value>int. The unique ID assigned to the work item instance.</value>
        public virtual int WorkItemID
        {
            get
            {
                return _workItemID;
            }
        }

        /// <summary>
        /// Gets or sets the title of the work item.
        /// </summary>
        /// <value>string. The title of the work item.</value>
        public virtual string Title { get; set; }

        /// <summary>
        /// Gets or sets the detailed description of the work item.
        /// </summary>
        /// <value>string. The detailed description of the work item.</value>
        public virtual string Description { get; set; }

        /// <summary>
        /// Gets the date and time the work item was created.
        /// </summary>
        /// <value>The date and time the work item was created.</value>
        public virtual DateTime Created
        {
            get { return _created; }
        }

        /// <summary>
        /// Gets the date and time the work item was modified.
        /// </summary>
        /// <value>The date and time the work item was modified.</value>
        public virtual DateTime Modified
        {
            get { return _modified; }
        }

        /// <summary>
        /// Gets or sets the current status of the work item.
        /// </summary>
        /// <value>One of the values of <see cref="WorkItemStatus"/> that specifies the
        /// current status of the work item.</value>
        public virtual WorkItemStatus Status { get; set; }

        /// <summary>
        /// Gets or sets the current priority of the work item.
        /// </summary>
        /// <value>One of the values of <see cref="WorkItemPriority"/> that specifies the
        /// current priority of the work item.</value>
        public virtual WorkItemPriority Priority { get; set; }

        /// <summary>
        /// Gets a list of <see cref="WorkItem"/> instances that are related to this
        /// <see cref="WorkItem"/> instance.
        /// </summary>
        /// <value>A <see cref="IEnumerable{T}"/> that can be used to enumerate the
        /// <see cref="WorkItem"/> instances that are related to this <see cref="WorkItem"/>
        /// instance.</value>
        public virtual IEnumerable<WorkItem> RelatedWorkItems
        {
            get
            {
                return _relatedItems;
            }
        }

        /// <summary>
        /// Gets a list of <see cref="Comment"/> instances that have been added to this
        /// <see cref="WorkItem"/> instance.
        /// </summary>
        /// <value>A <see cref="IEnumerable{T}"/> that can be used to enumerate the
        /// <see cref="Comment"/> instances that are related to this <see cref="WorkItem"/>
        /// instance.</value>
        public virtual IEnumerable<Comment> Comments
        {
            get { return _comments; }
        }

        /// <summary>
        /// Gets a list of <see cref="Attachment"/> instances that have been added to this
        /// <see cref="WorkItem"/> instance.
        /// </summary>
        /// <value>A <see cref="IEnumerable{T}"/> that can be used to enumerate the
        /// <see cref="Attachment"/> instances added to this <see cref="WorkItem"/>
        /// instance.</value>
        public virtual IEnumerable<Attachment> Attachments
        {
            get { return _attachments; }
        }

        /// <summary>
        /// Gets the <see cref="Project"/> that this <see cref="WorkItem"/> instance
        /// belongs to.
        /// </summary>
        /// <value>The <see cref="Project"/> instance this <see cref="WorkItem"/> instance
        /// belongs to.</value>
        public virtual Project Project
        {
            get { return _project; }
        }

        /// <summary>
        /// Gets the <see cref="IUser"/> that created this <see cref="WorkItem"/> instance.
        /// </summary>
        /// <value>The <see cref="IUser"/> instnace that created this <see cref="WorkItem"/>
        /// instance.</value>
        public virtual IUser CreatedBy
        {
            get { return _createdBy; }
        }

        /// <summary>
        /// Gets or sets the <see cref="IUser"/> to whom this work item has been assigned.
        /// <value>The <see cref="IUser"/> instnce to whom this <see cref="WorkItem"/> instance
        /// has been assigned.</value>
        /// </summary>
        public virtual IUser AssignedTo { get; set; }

        
        #endregion

        #region methods
        /// <summary>
        /// Adds a work item as a related work item.
        /// </summary>
        /// <param name="relatedWorkItem">The <see cref="WorkItem"/> instnace to relate to.</param>
        /// <returns>The current <see cref="WorkItem"/> instance.</returns>
        public WorkItem AddRelatedWorkItem(WorkItem relatedWorkItem)
        {
            Guard.Against<ArgumentNullException>(relatedWorkItem == null,
                                                 "Cannot add a null work item as a related work item.");

            _relatedItems.Add(relatedWorkItem);
            relatedWorkItem._relatedItems.Add(this);
            return this;
        }

        /// <summary>
        /// Removes a related work item from the current work item's <see cref="RelatedWorkItems"/> list.
        /// </summary>
        /// <param name="relatedWorkItem">The <see cref="WorkItem"/> instance to remove.</param>
        /// <returns>The current <see cref="WorkItem"/> instance.</returns>
        public WorkItem RemoveRelatedWorkItem(WorkItem relatedWorkItem)
        {
            Guard.Against<ArgumentNullException>(relatedWorkItem == null,
                                                 "Cannot remove a null work item from the related work items list.");
            _relatedItems.Remove(relatedWorkItem);
            relatedWorkItem._relatedItems.Remove(this);
            return this;
        }

        /// <summary>
        /// Adds a comment to the work item.
        /// </summary>
        /// <param name="comment">The <see cref="Comment"/> instance to add to the work item.</param>
        /// <returns>The current work item.</returns>
        public WorkItem AddComment(Comment comment)
        {
            Guard.Against<ArgumentNullException>(comment == null, "Cannot add a null comment to the WorkItem.");
            _comments.Add(comment);
            comment.WorkItem = this;
            return this;
        }

        /// <summary>
        /// Removes a comment from the work item's <see cref="Comments"/> list.
        /// </summary>
        /// <param name="comment">The <see cref="Comment"/> instance to remove.</param>
        /// <returns>The current <see cref="WorkItem"/> instance.</returns>
        public WorkItem RemoveComment(Comment comment)
        {
            Guard.Against<ArgumentNullException>(comment == null,
                                                 "Cannot remove a null Comment instance from the comments list of the work item.");
            _comments.Remove(comment);
            comment.WorkItem = null;
            return this;
        }

        /// <summary>
        /// Adds an attachment to the work item.
        /// </summary>
        /// <param name="attachment">The <see cref="Attachment"/> instance to 
        /// add to the work item.</param>
        /// <returns>The current <see cref="WorkItem"/> instance.</returns>
        public WorkItem AddAttachment(Attachment attachment)
        {
            Guard.Against<ArgumentNullException>(attachment == null, "Cannot add a null Attachment to the Work Item.");
            _attachments.Add(attachment);
            attachment.WorkItem = this;
            return this;
        }

        /// <summary>
        /// Removes an attachment added to a work item.
        /// </summary>
        /// <param name="attachment">The <see cref="Attachment"/> to remove from the
        /// work item.</param>
        /// <returns>The current <see cref="WorkItem"/></returns>
        public WorkItem RemoveAttachment(Attachment attachment)
        {
            Guard.Against<ArgumentNullException>(attachment == null,
                                                 "Cannot remove a null Attachment from the work item's attachment list");
            _attachments.Remove(attachment);
            attachment.WorkItem = null;
            return this;
        }
        #endregion
    }
}
